package minimips
import (
	"fmt"
	"dumpwave"
//	"time"
)

func execute(
	decodeExecute	chan DEEX,
	execute_rd	chan int,
	executeDmem	chan EXDM,
	branch_decision	chan uint) {
	addr_offset:=uint(0)
	for{
		deex :=<- decodeExecute
		fmt.Printf("[execute] DEEX <-- DECODE: (op: 0x%x  |  function: 0x%x  | rs: 0x%x | rt: 0x%x)\n", deex.op, deex.function, deex.rs, deex.rt)
		
		switch deex.op {
			case 0x0:
				switch deex.function{
					case 0x20: //add
						fmt.Println(" [execute] Operação ADD --> DECODE:",deex.rs,"+",deex.rt)
						dumpwave.Wave(1,"execute_rdRA")
						dumpwave.Wave(deex.rs + deex.rt,"execute_rd")
						execute_rd <- deex.rs + deex.rt
						dumpwave.Wave(0,"execute_rdRA")
					case 0x22: //sub
						fmt.Println(" [execute] Operação SUB --> DECODE:",deex.rs,"-",deex.rt)
						dumpwave.Wave(1,"execute_rdRA")
						dumpwave.Wave(deex.rs - deex.rt,"execute_rd")
						execute_rd <- deex.rs - deex.rt
						dumpwave.Wave(0,"execute_rdRA")
					case 0x24: //and
						fmt.Println(" [execute] Operação AND --> DECODE:",deex.rs,"&",deex.rt)
						dumpwave.Wave(1,"execute_rdRA")
						dumpwave.Wave(deex.rs & deex.rt,"execute_rd")
						execute_rd <- deex.rs & deex.rt
						dumpwave.Wave(0,"execute_rdRA")
					case 0x25: //or
						fmt.Println(" [execute] Operação OR --> DECODE:",deex.rs,"|",deex.rt)
						dumpwave.Wave(1,"execute_rdRA")
						dumpwave.Wave(deex.rs | deex.rt,"execute_rd")
						execute_rd <- deex.rs | deex.rt
						dumpwave.Wave(0,"execute_rdRA")
					default:
						fmt.Println("[execute] default selecionado....")
						dumpwave.Wave(1,"execute_rdRA")
						dumpwave.Wave(0,"execute_rd")
						execute_rd <- 0
						dumpwave.Wave(0,"execute_rdRA")
				}
			case 0x08: //addi
						fmt.Println(" [execute] Operação ADDI --> DECODE:",deex.rs,"+",deex.rt)
						dumpwave.Wave(1,"execute_rdRA")
						dumpwave.Wave(deex.rs + int(deex.offset),"execute_rd")
						execute_rd <- deex.rs + int(deex.offset)
						dumpwave.Wave(0,"execute_rdRA")
			case 0x4: //beq
				fmt.Println(" [execute] Operação BEQ --> FETCH")
				if deex.rs == deex.rt {
					dumpwave.Wave(1,"branch_decisionRA")
					dumpwave.Wave(1,"branch_decision")
					branch_decision <- 1;
					fmt.Println(" [execute] branch_decision = 1")
					dumpwave.Wave(0,"branch_decisionRA")
				} else{
					dumpwave.Wave(1,"branch_decisionRA")
					dumpwave.Wave(0,"branch_decision")
					branch_decision <- 0;
					fmt.Println(" [execute] branch_decision = 0")
					dumpwave.Wave(0,"branch_decisionRA")
				}
				
			case 0x23: //lw
				fmt.Println(" [execute] Operação LW")
				if  uint(deex.offset & 0x8000) == uint(0) {
						addr_offset = 0x00000000
				}else {
						addr_offset = 0xFFFF0000
				}
				addr_offset = addr_offset | (deex.offset & 0xFFFF)
				fmt.Printf("[execute] EXDM --> DMEM (rs: 0x%x addr_offset: 0x%x)\n",deex.rs,addr_offset)
				dumpwave.Wave(1,"executeDmemRA")
				fmt.Printf("****lw %d\n", int(addr_offset))
				dumpwave.Wave(deex.rs + int(addr_offset),"executeDmem")
				executeDmem <- EXDM{addr: deex.rs + int(addr_offset), read_write: uint(1)}
				dumpwave.Wave(0,"executeDmemRA")
				
			case 0x2B: //sw
				fmt.Println(" [execute] Operção SW")
				if  uint(deex.offset & 0x8000) == uint(0) {
						addr_offset = 0x00000000
				}else {
						addr_offset = 0xFFFF0000
				}
				addr_offset = addr_offset | (deex.offset & 0xFFFF)
				fmt.Printf("[execute] EXDM --> DMEM (rs: 0x%x addr_offset: 0x%x)\n",deex.rs,addr_offset)
				dumpwave.Wave(1,"executeDmemRA")
				fmt.Printf("****sw %d\n", int(addr_offset))
				dumpwave.Wave(deex.rs + int(addr_offset),"executeDmem")
				executeDmem <- EXDM{addr: deex.rs + int(addr_offset), read_write: uint(0)}
				dumpwave.Wave(0,"executeDmemRA")
			default:
				fmt.Println("ERRO: Instrução ilegal [execute]")
			 }
	 }
}